//---HEADER
//	Name:	Haptik Library
//	Desc:	Plugin Development Header
//	Auto:	Maurizio de Pascale
//	Date:	July 17th 2005
//	Tabs:	tabbed at 3
//	Http:	www.haptiklibrary.org
//	Svns:	$Revision: 39 $
//			$Date: 2005-12-03 16:24:01 +0100 (sab, 03 dic 2005) $
//------------------------------------------------------------>
#ifndef ___HAPTIK_PLUGIN___
#define ___HAPTIK_PLUGIN___
 
 
 
//---INCLUDE
//------------------------>
#include <RSLib_OLD/Haptik.hpp>
 
 
 
//---NAMESPACE
//------------->
namespace RSLib {
 
 
 
//---INTERFACE
//	Desc:	Interface exposed by the library to the plugins. Used for 1) centralized services 2) reference counting 3) internal recursion
//	Note:	This is a weak interface... no need to call Release()
//	Todo:	Eventually include Release in 1.1...
//------------------------------------------------------------------------------------------------------------------------------------>
typedef class IHaptikLibraryLower
{
	public:
//	configuration file access	
	virtual PCHAR8 GetVariable(IN PCHAR8 name) PURE;
	virtual UINT32 SetVariable(IN PCHAR8 name,IN PCHAR8 value) PURE;
	
//	reference count management
	virtual UINT32 Lock() PURE;
	virtual UINT32 Unlock() PURE;
	
//	access to other devices for internal recursion
	virtual UINT32 GetNumberOfDevices() PURE;
	virtual UINT32 GetDeviceInfo(IN UINT32 deviceId,OUT HaptikDeviceInfoPtr pDev) PURE;
	virtual PVOID GetDeviceInterface(IN UINT32 deviceId,IN UINT32 interfaceId) PURE;
	
//	logging
	virtual UINT32 Log(IN PCHAR8 message) PURE;
}*IHaptikLibraryLowerInterface;
 
 
 
//---INTERFACE
//	Desc:	Interface exposed by plugins and used by the library
//----------------------------------------------------------->
typedef class IHaptikPlugin
{
	public:
	virtual UINT32 Init(IN IHaptikLibraryLowerInterface libraryInterface,IN UINT32 pluginId) PURE;
	virtual UINT32 Release() PURE;
	
	virtual UINT32 GetNumberOfDevices() PURE;
	virtual UINT32 GetDeviceInfo(IN UINT32 deviceId,OUT HaptikDeviceInfoPtr pDev) PURE;
	
	virtual PVOID GetDeviceInterface(IN UINT32 deviceId,IN UINT32 interfaceId) PURE;
	
	virtual UINT32 GetPluginInfo(OUT HaptikPluginInfoPtr pInfo) PURE;
	
}*IHaptikPluginInterface;
 
 
 
//---TYPEDEF
//	Desc:	Plugin Dll entry point type
//------------------------------------------------------------->
extern "C" {typedef PVOID (*HAPTIK_PLUGIN_ENTRY_PROC) (UINT32);}
 
 
 
//---UTILITIES
//	Desc:	Asm code for method/procedure invocation
//	Note:	A "dangerous" always restoring frame is implemented which gets identified as warning by the compiler
//			It allows for invocation of methods with wrong number of arguments that do not mess the caller frame
//----------------------------------------------------------------------------------------------------------->
#ifdef RS_WINDOWS
#pragma warning(push)
#pragma warning( disable : 4731 )
inline void InvokeCallback(PVOID method,PVOID object,PVOID argument1,PVOID argument2)
{
	__asm
	{
		mov ecx,object		//mov input arguments to registers
		mov eax,method
		mov ebx,argument1
		mov edx,argument2

		push ebp			//save old ebp
		mov ebp,esp		//store before-call esp. LOCALS ARE NO MORE ACCESSIBLE!

		push edx			//push argument2
		push ebx			//push argument1
		call eax			//call method(procedure)

		mov esp,ebp		//restore before-call esp.
		pop ebp			//pop old ebp. LOCALS ARE ACCESSIBLE!
	}
}
#pragma warning( pop )
#endif//RS_WINDOWS
 
#ifdef RS_LINUX
void __attribute__((weak)) InvokeCallback(PVOID method,PVOID object,PVOID argument1,PVOID argument2)
{
//!NOTE: the GCC inline assembly looks very buggy and the compiler does panic easily if a non trivial
//			registers reuse is to be done... unfortunately I haven't found a robust way to load stuff from C
//			into registers without using this "extended" syntax
	asm volatile(
		"pushl %%ebx\r\n"
		
		"mov 0xC(%%eax), %%edx\r\n"	//mov edx,argument2		//mov input arguments to registers
		"mov 0x8(%%eax), %%ebx\r\n"	//mov ebx,argument1
		"mov 0x4(%%eax), %%ecx\r\n"	//mov ecx,object
		"mov 0x0(%%eax), %%eax\r\n"	//mov eax,method
 
		"pushl %%ebp\r\n"
		"movl %%esp,%%ebp\r\n"			//mov ebp,esp			//store before-call esp. LOCALS ARE NO MORE ACCESSIBLE!
		
		"pushl %%edx\r\n"					//push edx				//push argument2
		"pushl %%ebx\r\n"					//push ebx				//push argument1
		"test %%ecx,%%ecx\r\n"			//if (ecx != 0)
		"jz 5\r\n"							//	skip push ecx
		"pushl %%ecx\r\n"					//push ecx				//GCC DOESN'T USE FASTCALL
		"call *%%eax\r\n"					//call method(procedure)

		"movl %%ebp,%%esp\r\n"			//mov esp,ebp			//restore before-call esp.
		"popl %%ebp\r\n"					//pop ebp				//pop old ebp. LOCALS ARE ACCESSIBLE!
		
		"popl %%ebx\r\n"

		:: "a"(&method)
		: "%ecx", "%edx"
		);
}
#endif//RS_LINUX
 
 
};//namespace RSLib
 
 
 
//---CONSTANTS
//----------------------------------------------->
#define HAPTIK_IHAPTIKLIBRARYLOWER		0x80008021
 
 
 
//---MACROS
//--------------------------------------------->
#define IS_ORDINAL(id)		(!(id & 0x80000000))
#define ISNT_ORDINAL(id)	(id & 0x80000000)

#define HARDWAREID(id)		((id & 0x0000FFFF)>>0)
#define PLUGINID(id)			((id & 0x00FF0000)>>16)
#define NUMBER(id)			((id & 0x1F000000)>>24)
#define FLAGS(id)				((id & 0xE0000000)>>29)

#define MATCH_DEVICEID(a,b)			( ((a & 0x0000FFFF) == 0xFFFF) || ((a & 0x1F00FFFF) == (b & 0x1F00FFFF)) )
#define MATCH_PLUGINID(a,b)			( ((a & 0x00FF0000) == 0x00FF0000) || (PLUGINID(a) == b) )
#define UNMATCH_DEVICEID(a,b)			(!MATCH_DEVICEID(a,b))
#define UNMATCH_PLUGINID(a,b)			(!MATCH_PLUGINID(a,b))

#define FLAGGED_DEVICEID(flags,number,pluginid,hardwareid)	( ((flags & 0x07)<<29) | ((number & 0x1F)<<24) | ((pluginid & 0xFF)<<16) | ((hardwareid& 0xFFFF)<<0) )
#define DEVICEID(number,pluginid,hardwareid)						( ((0x004 & 0x07)<<29) | ((number & 0x1F)<<24) | ((pluginid & 0xFF)<<16) | ((hardwareid& 0xFFFF)<<0) )
 
 
 
#endif//___HAPTIK_PLUGIN___